// tmweb demo

FPS = 10;
frame = 0;
key = new Array(256);

// some map offset stuff
vx = 0;
vy = 0;

first_update = true;
net_status = '';
chat_message = '';
server_time = 0;

osd_duration = 0;
osd_message = "";

function LoadMapFromLocation() {
  // request server/location.php and set up propper map
  
  // which map to load?
  var xtr = new PuXtr('server/location.php','');
  // if it is empty (first run), just put me to hurnscald
  if (xtr.row.length <= 0) {
    var map_src = 'maps/009-1.tmx';
    var map_x0 = 1520;
    var map_y0 = 1120;
  } else {
    // get read data
    var map_src = xtr.row[0].getAttribute('v_filename');
    var map_x0 = 1*xtr.row[0].getAttribute('i_x');
    var map_y0 = 1*xtr.row[0].getAttribute('i_y');
  }
  ///debug('  map: x0='+Math.floor(map_x0/32-10)+' y='+(map_y0/32-7));
  
  // load map
  map = new Map(map_src);

  // initial map offset is important for first drawing of the map, otherwis it will be lagish (part of map will be white for a while)
  map.x0 = Math.floor(map_x0/32) - 10;
  map.y0 = Math.floor(map_y0/32) - 7;
}

function onLoginDone(AIUser,AVNick) {
  // logged in
  i_user = AIUser;
  ///debug('i_user='+AIUser+' v_nick='+AVNick);
  // initialize canvas
  canvas = document.getElementById('canvas');
	context = canvas.getContext('2d');

  // sprite lookup (eqty + race/any = sprite xml?)
  sprite_lookup = new SpriteLookup('server/spri.php');
  
  // load sprites to combo boxes
  ItemsSelects();

  // array of all avatars
  avatars = new Avatars();

  // me
  var me = new Avatar('male',4);
  me.x = 48*32;
  me.y = 33*32;
  me.user = AIUser;
  avatars.push(me);
  avatar_update = new AvatarUpdate(me);
  
/*  
  // female (just for testing)
  var female = new Avatar('female',4);
  female.x = 43*32-16;
  female.y = 32*32;
  female.update('attack','left');
  avatars.push(female);
*/
  
  // testing monsters (not real avatars yet, they will stay on same spot!)
  /*
  snake = new MetaSprite(monster_snake_cave);
  snake.update('walk','right');
  
  zombie = new MetaSprite(monster_zombie);
  zombie.update('walk','down');
  */

  LoadMapFromLocation();

/*
  // selects for action/animation   
  document.getElementById('selAction1').value = avatars[0].action;
  document.getElementById('selAnimation1').value = avatars[0].animation;

*/  

  // drawing timer
  setInterval('draw()',1000/FPS);
  
  // network update timer
  setInterval('networkUpdate()',500);
  
  // first asta update
  astaUpdate();
}

function onLoad() {
  var xtr = new PuXtr('purin2/user/xtr/cookies.php','');
  var i_user = xtr.row[0].getAttribute('i_user');
  var v_nick = xtr.row[0].getAttribute('v_nick');
  pu_user_csrf = xtr.row[0].getAttribute('pu_user_csrf');
  ///alert("i_user="+i_user+" v_nick="+v_nick+" pu_user_csrf="+pu_user_csrf);
  onLoginDone(i_user,v_nick);
}

function draw() {
  // draw scene

  // warp
  warpAvatar();

  // clear canvas
  context.clearRect(0,0,640,480);

  // skip draw (for debug purposes)
  if (document.getElementById('stop').checked)
    return false;
	
  // manual map pan
  map.pan();
  
  // discrete autopan - pure dizzynes
  if (avatars.length > 0) {
    // discrete part
    if (avatars[0].x - (map.x0+10)*32 > 0) map.x0++;
    if (avatars[0].x - (map.x0+10)*32 < 0) map.x0--;
    if (avatars[0].y - (map.y0+7)*32 > 0) map.y0++;
    if (avatars[0].y - (map.y0+7)*32 < 0) map.y0--;
    // do not pan more than possible
    if (map.x0 < 0) map.x0 = 0;
    if (map.y0 < 0) map.y0 = 0;
    // calculate centering vector
    vx = avatars[0].x - (map.x0+10)*32;
    vy = avatars[0].y - (map.y0+7)*32;
  }

  // which layers to draw
  /*
  var l1 = document.getElementById('chbLayer1').checked;
  var l2 = document.getElementById('chbLayer2').checked;
  var l3 = document.getElementById('chbLayer3').checked;
  var l4 = document.getElementById('chbLayer4').checked;
  var l5 = document.getElementById('chbLayer5').checked;
  */

  // my avatar
  if (document.activeElement.id != 'chat')
    avatars.movement(key);
  
  // map background (lets assume ground and fringe is always here)
  map.draw(map.x0,map.y0,20+1,15+3,map.ground,map.fringe);
  
  // draw sprite
  context.save();
  context.translate(0,0);

  // testing monsters
  //snake.draw(300,200);
  //zombie.draw(380,250);

  // map foreground (player never can be above "top" or "over" layer)
  if (map.top >= 0) map.draw(map.x0,map.y0,20,15+3,map.top,map.top);
  if (map.over >= 0) map.draw(map.x0,map.y0,20,15+3,map.over,map.over);
  //if (map.collision >= 0) map.draw(map.x0,map.y0,20,15+3,map.collision,map.collision);
  
  // display loader info
  loader.draw();
  
  // draw net_status
  context.font = "bold 12pt courier";
  context.fillStyle = "rgba(255,255,0,0.8)";
  context.textAlign = "left";
  context.fillText(net_status,10,16);

  // draw osd message
  if (osd_duration > 0) {
    osd_duration--;
    context.font = "bold 12pt courier";
    context.fillStyle = "rgba(255,0,255,1.0)";
    context.textAlign = "center";
    context.fillText(osd_message,320,200);
  }

  // finish drawing
  frame++;

  context.restore();
}

function test() {
  debug('test()');
  updatePlayer();
}

function test2() {
  debug('test2()');
  chest_assassin_male.draw(100,100);
}

function OnChangeFeet(AThis,AEvent) {
	var v = 1*AThis.value;
	if (v==0) avatars[0].feet = null; else avatars[0].feet = new MetaSprite(v,avatars[0].race);
  avatars[0].update(avatars[0].action,avatars[0].animation);
  AThis.blur();
}

function OnChangeHairstyle(AThis,AEvent) {
	var v = 1*AThis.value;
  // bald?
  if (v==0) { 
    avatars[0].hairstyle = null;
    AThis.blur();
    return;
  }
  // change but keep color
  if (color_picker_red >= 0) {
    var src = sprite_lookup[v+'_any'].xml;
    /// alert(src);
    avatars[0].hairstyle.sprite = new Sprite(src,2*color_picker_red,2*color_picker_green,2*color_picker_blue);
  } else {
    // simple change
    avatars[0].hairstyle = new MetaSprite(v,avatars[0].race);
  }
  avatars[0].update(avatars[0].action,avatars[0].animation);
  AThis.blur();
}

function OnChangeHands(AThis,AEvent) {
	var v = 1*AThis.value;
  if (v==0) avatars[0].hands = null; else avatars[0].hands = new MetaSprite(v,avatars[0].race);
  avatars[0].update(avatars[0].action,avatars[0].animation);
  AThis.blur();
}

function OnChangeHead(AThis,AEvent) {
	var v = 1*AThis.value;
  if (v==0) avatars[0].head = null; else avatars[0].head = new MetaSprite(v,avatars[0].race);
  avatars[0].update(avatars[0].action,avatars[0].animation);
  AThis.blur();
}

function OnChangeChest(AThis,AEvent) {
	var v = 1*AThis.value;
  if (v==0) avatars[0].chest = null; else avatars[0].chest = new MetaSprite(v,avatars[0].race);
  avatars[0].update(avatars[0].action,avatars[0].animation);
  AThis.blur();
}

function OnChangeLeg(AThis,AEvent) {
	var v = 1*AThis.value;
  if (v==0) avatars[0].leg = null; else avatars[0].leg = new MetaSprite(v,avatars[0].race);
  avatars[0].update(avatars[0].action,avatars[0].animation);
  AThis.blur();
}

function ChangeRace(AAvatar,ARace) {
  // rather complex function to change the race
  if (AAvatar.race == ARace)
    return;
  if (!ARace)
    ARace = 'male';
	AAvatar.race = ARace;
  AAvatar.body = new MetaSprite(AAvatar.body.eqty,ARace);
  // remember hair colors
  if (AAvatar.hairstyle) {
    var r = AAvatar.hairstyle.sprite.red;
    var g = AAvatar.hairstyle.sprite.green;
    var b = AAvatar.hairstyle.sprite.blue;
    AAvatar.hairstyle = new MetaSprite(AAvatar.hairstyle.eqty,'any');
    AAvatar.hairstyle.sprite = new Sprite(AAvatar.hairstyle.sprite.filename,r,g,b);
  }
	AAvatar.leg       = new MetaSprite(AAvatar.leg.eqty,ARace);
	AAvatar.chest     = new MetaSprite(AAvatar.chest.eqty,ARace);
	AAvatar.feet      = new MetaSprite(AAvatar.feet.eqty,ARace);
  if (AAvatar.hands) // some opera fixes
    AAvatar.hands     = new MetaSprite(AAvatar.hands.eqty,ARace);
  if (AAvatar.head)  // some opera fixes
    AAvatar.head      = new MetaSprite(AAvatar.head.eqty,'any'); 	
//  if (v==0) avatars[0].race = null; else avatars[0].body = new MetaSprite(v,avatars[0].race);
  AAvatar.update(AAvatar.action,AAvatar.animation);
}

function OnChangeRace(AThis,AEvent) {
	var v = AThis.value;
	if (v == '0')
		return;
  ChangeRace(avatars[0],v);
}

function updatePlayer() {
  avatars[0].update(avatars[0].action,avatars[0].animation);
}

function bodyOnKeyDown(AThis,AEvent) {
  // key pressed
  // remember pressed keys
  //debug('dn: '+AEvent.keyCode);
  key[AEvent.keyCode] = true;
  if ((AEvent.keyCode == 37)
    ||(AEvent.keyCode == 38)
    ||(AEvent.keyCode == 39)
    ||(AEvent.keyCode == 40) )
    return (document.activeElement.id == 'chat');
}

function bodyOnKeyUp(AThis,AEvent) {
  // key released
  // focus chat if enter is pressed
  if (AEvent.keyCode == 13)
    if (document.activeElement.id != 'chat')
      document.getElementById('chat').focus();
  // remember that key was released
  //debug('up: '+AEvent.keyCode);
  key[AEvent.keyCode] = false;
  if ((AEvent.keyCode == 37)
    ||(AEvent.keyCode == 38)
    ||(AEvent.keyCode == 39)
    ||(AEvent.keyCode == 40) )
    return (document.activeElement.id == 'chat');
}

function ChangeEquipmentColor(AGear) {
  // change color of gear
  ColorPicker("ChangeEquipmentColorCallback('"+AGear+"')");
}

function ChangeEquipmentColorCallback(AGear) {
  ///debug('ChangeEquipmentColorCallback: '+AGear);
  // change hairstyle color now
  if (AGear == "hairstyle") {
    var src = avatars[0].hairstyle.sprite.imageset[0].src.replace('.png','.xml');
    ///debug('  hairstyle: src='+src+' rgb='+(2*color_picker_red)+','+(2*color_picker_green)+','+(2*color_picker_blue));
    avatars[0].hairstyle.sprite = new Sprite(src,2*color_picker_red,2*color_picker_green,2*color_picker_blue);
  }
}

function networkUpdate() {
  // network update called every 500ms or so
  if (!loader.busy())
    astaUpdate();
  else
    net_status = 'busy';
}

function astaUpdate() {
  // send my position update to server & receive other player info
  //debug("astaUpdate: started at "+(new Date()).getTime())
  net_status = '----';
  avatar_update.update(astaUpdateDone,!first_update,chat_message);
  chat_message = '';
  first_update = false;
}

function astaUpdateDone(AXml,AParams) {
  // parse received answer from server/asta.php
  var xtr = puXtrValidate(AXml,AParams);
  var sta = puXtrStatus(xtr);
  if (sta[0] != 0)
    throw sta[0]+': '+sta[1];
  ///debug(sta[0]+': '+sta[1]);
  var row = puXtrRow(xtr);
  
  // just get the friken server time from enybody
  if (row.length > 0)
    server_time = 1*row[0].getAttribute('i_server');

  // remember if avatar was updated in this update, if no, it has to be spliced!
  for (var i=0; i<avatars.length; i++)
    avatars[i].updated_recently = false;

  // use every row for update (except mine, don't update that one)
  for (var i=0; i<row.length; i++) {
    //
    var pom_user = row[i].getAttribute('j_user');
    //debug('row['+i+']: j_user='+pom_user+'/me:'+i_user+' ');
    // ignore my own avatar change
    if (i_user == pom_user) {
      if (avatars[0].initialized) {
        avatars[0].chat = row[i].getAttribute('v_chat');
        avatars[0].chat_time = 1*row[i].getAttribute('i_chat');
        avatars[0].updated_recently = true;
        continue;
      }
      // first time initialization of my onw avatar
      avatars[0].race = row[i].getAttribute('v_race');
      if (!avatars[0].race)
        avatars[0].race = 'male'; // NOTE: some hack on first login
      avatars[0].body = new MetaSprite(-100,avatars[0].race);
      avatars[0].x = 1*row[i].getAttribute('i_x');
      avatars[0].y = 1*row[i].getAttribute('i_y');
      // my clothes
      avatars[0].leg       = new MetaSprite(1*row[i].getAttribute('j_leg'),avatars[0].race);
      avatars[0].chest     = new MetaSprite(1*row[i].getAttribute('j_chest'),avatars[0].race);
      avatars[0].feet      = new MetaSprite(1*row[i].getAttribute('j_feet'),avatars[0].race);
      avatars[0].hands     = new MetaSprite(1*row[i].getAttribute('j_hands'),avatars[0].race);
      avatars[0].head      = new MetaSprite(1*row[i].getAttribute('j_head'),'any'); 
      // hair color
      if (!avatars[0].hairstyle) {
        var jh = 1*row[i].getAttribute('j_hair');
        if (jh != 0) {
          avatars[0].hairstyle = new MetaSprite(jh,avatars[0].race);
          avatars[0].hairstyle.sprite = new Sprite(avatars[0].hairstyle.sprite.filename,1*row[i].getAttribute('i_red'),1*row[i].getAttribute('i_green'),1*row[i].getAttribute('i_blue'));
        }
      } else
        avatars[0].hairstyle.sprite = new Sprite(avatars[0].hairstyle.sprite.filename,1*row[i].getAttribute('i_red'),1*row[i].getAttribute('i_green'),1*row[i].getAttribute('i_blue'));
      avatars[0].update(row[i].getAttribute('v_action'),row[i].getAttribute('v_animation'));
      avatars[0].initialized = true;
      avatars[0].chat = row[i].getAttribute('v_chat');
      avatars[0].chat_time = 1*row[i].getAttribute('i_chat');
      server_time = 1*row[i].getAttribute('i_server');
      updateEquipment();
      avatars[0].updated_recently = true;
    }
    // place all other avatars
    // is there such avatar allready?
    var a = avatars.byUser(pom_user);
    //debug('  avatar = '+a);
    if (a!=null) {
      // asta is already in avatars[], only update attributes
      //debug('  updating existing avatar');
      
      // do not actualy update avatars position, only set desired future position
      //a.x = 1*row[i].getAttribute('i_x');
      //a.y = 1*row[i].getAttribute('i_y');
      a.fx = 1*row[i].getAttribute('i_x');
      a.fy = 1*row[i].getAttribute('i_y');

      a.chat = row[i].getAttribute('v_chat');
      a.chat_time = 1*row[i].getAttribute('i_chat');
      server_time = 1*row[i].getAttribute('i_server');
      a.update(row[i].getAttribute('v_action'),row[i].getAttribute('v_animation'));
      a.updated_recently = true;
      
      // race change (if required)
      ChangeRace(a,row[i].getAttribute('v_race'));

      function EqtyChange(AMetaSprite,AEqty) {
        // aux. function, return true if given sprite has differenty eqty
        var c = 0;
        if (AMetaSprite.eqty) c = AMetaSprite.eqty;
        return c != 1*row[i].getAttribute(AEqty);
      }
      // equipment changes
      if (EqtyChange(a.leg,'j_leg'))
        a.leg       = new MetaSprite(1*row[i].getAttribute('j_leg'),a.race);
      if (EqtyChange(a.chest,'j_chest'))
        a.chest     = new MetaSprite(1*row[i].getAttribute('j_chest'),a.race);
      if (EqtyChange(a.feet,'j_feet'))
        a.feet      = new MetaSprite(1*row[i].getAttribute('j_feet'),a.race);
      if (EqtyChange(a.hands,'j_hands'))
        a.hands     = new MetaSprite(1*row[i].getAttribute('j_hands'),a.race);
      if (EqtyChange(a.head,'j_head'))
        a.head      = new MetaSprite(1*row[i].getAttribute('j_head'),'any'); 
      
      // hairstyle change (need extra test because of stupid negative haircuts)
      var c = 0;
      var h_red = -1;
      var h_green = -1;
      var h_blue = -1;
      if (a.hairstyle) {
        c = a.hairstyle.eqty;
        try {
        h_red = 1*a.hairstyle.sprite.red;
        h_green = 1*a.hairstyle.sprite.green;
        h_blue = 1*a.hairstyle.sprite.blue;
        } catch(e) {
        h_red = -1;
        h_green = -1;
        h_blue = -1;
        } 
      }
      var n_red = 1*row[i].getAttribute('i_red');
      var n_green = 1*row[i].getAttribute('i_green');
      var n_blue = 1*row[i].getAttribute('i_blue');
      var color_change = ( (h_red!=n_red)||(h_green!=n_green)||(h_blue!=n_blue) );
      var nh = 1*row[i].getAttribute('j_hair');
      ///debug('testing hairchange... c='+c+' nh='+nh+' cc='+color_change+' rgb1='+h_red+','+h_green+','+h_blue+' rgb2='+n_red+','+n_green+','+n_blue);
      if ((nh != c)||color_change) {
        ///debug('hairchange to: '+nh);
        if (nh != 0) {
          a.hairstyle = new MetaSprite(nh,a.race);
          a.hairstyle.sprite = new Sprite(a.hairstyle.sprite.filename,1*row[i].getAttribute('i_red'),1*row[i].getAttribute('i_green'),1*row[i].getAttribute('i_blue'));
        }
        ///debug('hairchanged to: '+a.hairstyle.eqty);
        a.update(row[i].getAttribute('v_action'),row[i].getAttribute('v_animation'));
      }
    
    } else {
      // asta not yet in avatars[], must create brand new avatar
      //debug('  creating NEW avatar');
      var a = new Avatar(row[i].getAttribute('v_race'),-1*row[i].getAttribute('j_hair'));
      a.race = row[i].getAttribute('v_race');
      a.body = new MetaSprite(-100,a.race);
      a.x = 1*row[i].getAttribute('i_x');
      a.y = 1*row[i].getAttribute('i_y');
      a.fx = 1*row[i].getAttribute('i_x');
      a.fy = 1*row[i].getAttribute('i_y');
      a.user = pom_user;
      //debug('  race='+a.race+' x='+a.x+' y='+a.y+' user='+a.user);
      // hair color
      if (!a.hairstyle) {
        try {
        a.hairstyle = new MetaSprite(1*row[i].getAttribute('j_hair'),a.race);
        a.hairstyle.sprite = new Sprite(a.hairstyle.sprite.filename,1*row[i].getAttribute('i_red'),1*row[i].getAttribute('i_green'),1*row[i].getAttribute('i_blue'));
        } catch(e) {
          // NOTE: deployment fix
        }
      } else
        a.hairstyle.sprite = new Sprite(a.hairstyle.sprite.filename,1*row[i].getAttribute('i_red'),1*row[i].getAttribute('i_green'),1*row[i].getAttribute('i_blue'));
      // clothes
      a.leg       = new MetaSprite(1*row[i].getAttribute('j_leg'),a.race);
      a.chest     = new MetaSprite(1*row[i].getAttribute('j_chest'),a.race);
      a.feet      = new MetaSprite(1*row[i].getAttribute('j_feet'),a.race);
      a.hands     = new MetaSprite(1*row[i].getAttribute('j_hands'),a.race);
      a.head      = new MetaSprite(1*row[i].getAttribute('j_head'),'any'); 
      a.chat = row[i].getAttribute('v_chat');
      a.chat_time = 1*row[i].getAttribute('i_chat');
      server_time = 1*row[i].getAttribute('i_server');
      a.update(row[i].getAttribute('v_action'),row[i].getAttribute('v_animation'));
      a.updated_recently = true;
      avatars.push(a);
    }
  }
  // splice avatars that has not been updated in this update
  for (var i=avatars.length-1; i>0; i--)
    if (!avatars[i].updated_recently) {
      //debug('splice avatar '+i);
      avatars.splice(i,1);
    }

  ///debug('astaUpdateDone: duration='+avatar_update.duration());
  net_status = avatar_update.duration();
}

function updateEquipment() {
  // set values of equipment selects according to my avatar actual gear
  if (avatars[0].head) document.getElementById('selHead1').value = avatars[0].head.eqty;
  if (avatars[0].hairstyle) document.getElementById('selHairstyle1').value = avatars[0].hairstyle.eqty;
  if (avatars[0].chest) document.getElementById('selChest1').value = avatars[0].chest.eqty;
  if (avatars[0].leg) document.getElementById('selLeg1').value = avatars[0].leg.eqty;
  if (avatars[0].feet) document.getElementById('selFeet1').value = avatars[0].feet.eqty;
  if (avatars[0].hands) document.getElementById('selHands1').value = avatars[0].hands.eqty;
  if (avatars[0].race) document.getElementById('selRace1').value = avatars[0].race;
}

function onChatKeyUp(AThis,AEvent) {
  // send chat message
  if (AEvent.keyCode == 13) {
    chat_message = AThis.value;
    AThis.value = '';
    setTimeout('document.getElementById("chat").blur();',200);
  }
}

warp_old_x = 0;
warp_old_y = 0;

function warpAvatar() {
  // detect if avatar step on warp point
  if (!avatars[0].initialized)
    return;
  // skip test if i'm standing at the same spot as before
  if ( (avatars[0].x == warp_old_x) && (avatars[0].y == warp_old_y) )
    return;
  // remember current warp poin to not cal it all the timne
  ///debug("zzz: ax="+avatars[0].x+" wox="+warp_old_x+" ay="+avatars[0].y+" woy="+warp_old_y);
  warp_old_x = avatars[0].x;
  warp_old_y = avatars[0].y;
  // am i at warp point?
  var index = avatars[0].x+','+avatars[0].y;
  if (map.warp[index]) {
    // yes, do the warp
    var nx = map.warp[index].mapX-32;
    var ny = map.warp[index].mapY-32-32; // NOTE: weird bug in entering hurnscald inn
    ///debug('warping to: map='+map.warp[index].map+' mapX='+nx+' mapY='+ny);
    // warp
    try {
      var xtr = PuXtr('server/warp.php','v_filename=maps/'+map.warp[index].map+'.tmx&i_x='+nx+'&i_y='+ny+'&pu_user_csrf='+pu_user_csrf);
    } catch(e) {
      //alert('Sorry, area you are trying to enter is not available at the moment!');
      osd_duration = 30;
      osd_message = "This map area not yet available!";
      throw e;
      return;
    }
    // set my new position  
    avatars[0].x = nx;
    avatars[0].y = ny;
    warp_old_x = nx;
    warp_old_y = ny;
    // clear other avatars
    var s1 = avatars.movement;   // NOTE: nasty slice hack, avatars should have been avatars.items in fact, not plain array
    var s2 = avatars.byUser;
    avatars = avatars.splice(0,1);
    avatars.movement = s1;
    avatars.byUser = s2;
    // load new map
    LoadMapFromLocation();
  }
}